<?php
	/**
	  * @package	MyTools
	  * @name		Installer
	  * @brief		Clase para ejecutar paquetes de instalacion realizados con la clase InstallBuilder
	  * @author		Hermann D. Schimpf <hschimpf@gschimpf.com>
	  * @license	http://opensource.org/licenses/gpl-2.0.php
	  * @date		2010-01-14
	  * @version	0.1.0
  	**/

	final class Installer extends MyDebuger implements MyVersions {
		/* version de la clase */
		private static $version			= 0;
		/* subversion de la clase */
		private static $subversion		= 1;
		/* numero de revision de la clase */
		private static $revision		= 0;

		/* estado del instalador */
		private $status		= False;
		/* datos de la instalacion */
		private $installData	= False;
		/* titulo del paquete */
		private $title			= False;
		/* autor del paquete */
		private $author		= False;
		/* descripcion del paquete */
		private $descrip		= False;
		/* bandera de DBs */
		private $withDBs		= False;
		/* objeto MySQLProcess */
		private $dbBuilder	= False;
		/* arbol de directorios */
		private $tree			= Array();
		/* ficheros a instalar */
		private $files			= Array();
		/* datos de la base de datos */
		private $dbData		= Array();

		public function __construct($title = __CLASS__, $author = __CLASS__, $descrip = Null, $withDBs = False) {
			/* creamos un mensaje inicial */
			if (isset($_POST[md5('configLoaded')])) {
				/* mostramos un mensaje */
				echo '<SCRIPT languaje=\'javascript\'>parent.Installer.show(\'Instalando paquete..\');';
				/* empezamos a mover el scroll */
				echo 'var autoScroll=setInterval(\'window.scrollBy(0,1000);\',25);</SCRIPT>';
				/* enviamos el cache */
				flush();
			}
			/* creamos el padre */
			parent::__construct(isset($_POST[md5('configLoaded')]), __CLASS__);
			/* almacenamos el titulo del paquete */
			$this->title = ($title === base64_encode(__CLASS__) ? __CLASS__ : base64_decode($title));
			/* almacenamos el author del paquete */
			$this->author = ($author === base64_encode(__CLASS__) ? __CLASS__ : base64_decode($author));
			/* verificamos si hay descripcion */
			if ($descrip !== Null)
				/* almacenamos la descripcion del paquete */
				$this->descrip = base64_decode($descrip);
			/* almacenamos las DBs */
			$this->withDBs = ($withDBs === True ? True : False);
		}

		public function __destruct() {
			/* creamos un mensaje inicial */
			if (isset($_POST[md5('configLoaded')]))
				/* dejamos de mover el scroll */
				echo '<SCRIPT languaje=\'javascript\'>setTimeout(\'clearInterval(autoScroll);\', 1000);</SCRIPT>';
			/* matamos el padre */
			parent::__destruct();
		}

		public static final function getVersion() {
			/* retornamos la version actual de la clase */
			return 'v' . self::$version . '.' . self::$subversion . '.' . self::$revision;
		}

		public function configLoaded() {
			/* ejecutamos el metodo privado, capturando las excepciones */
			$this->catchExceptions('verificarConfigLoaded');
			/* retornamos el estado */
			return $this->status;
		}

		public function getInstallConfig() {
			/* ejecutamos el metodo privado, capturando las excepciones */
			$this->catchExceptions('showInstallForm');
		}

		public function loadData($installData) {
			/* ejecutamos el metodo privado, capturando las excepciones */
			$this->catchExceptions('saveInstallData', $installData);
		}

		public function installPackage() {
			/* ejecutamos la instalacion del paquete */
			$this->catchExceptions('runInstall', True);
		}

		private function verificarConfigLoaded() {
			/* mostramos un mensaje */
			$this->show('Verificando si se especificaron las configuraciones..', False);
			/* almacenamos el estado de acuerdo a una cookie */
			$this->status = isset($_POST[md5('configLoaded')]);
			/* mostramos ok al mensaje */
			$this->showOK();
		}

		private function showInstallForm() {
			/* mostramos un mensaje */
			$this->show('Iniciando carga del formulario de configuraciones..');
			/* iniciamos el codigo HTML */
			echo '<HTML>';
			/* cargamos el head */
			$this->loadHeadHtml();
			/* cargamos el body */
			$this->loadBodyHtml();
			/* finalizamos el codigo HTML */
			echo '</HTML>';
		}

		private function loadHeadHtml() {
			/* mostramos un mensaje */
			$this->show('Cargando seccion HEAD..');
			/* iniciamos el head */
			echo '<HEAD>';
			/* cargamos el titulo */
			$this->loadTitleHtml();
			/* cargamos la hoja de estilos */
			$this->loadStyles();
			/* cargamos las funciones javascript */
			$this->loadJavaSctipt();
			/* finalizamos el head */
			echo '</HEAD>';
		}

		private function loadTitleHtml() {
			/* mostramos un mensaje */
			$this->show('Cargando titulo general..', False);
			/* cargamos el titulo de la aplicacion */
			echo '<TITLE>Instalacion del paquete - ' . $this->getTitle() . '</TITLE>';
			/* mostramos ok al mensaje */
			$this->showOK();
		}

		private function loadStyles() {
			/* mostramos un mensaje */
			$this->show('Cargando hoja de estilos..', False);
			/* iniciamos la etiqueta style */
			echo '<STYLE>';
			/* agregamos el estilo del body */
			$this->addStyle('body', 'font-family: Arial', 'margin: 40px 0px 0px 0px');
			/* agregamos el estilo de las tablas */
			$this->addStyle('table', 'border-collapse: collapse', 'border-spacing: 0px', 'border-style: solid', 'border-width: 1px', 'width: 600px');
			/* agregamos el estilo de las celdas */
			$this->addStyle('td', 'border-style: solid', 'border-width: 0px', 'text-align: center');
			/* agregamos el estilo de los campos */
			$this->addStyle('select,input,button,textarea', 'border-color: #AAA', 'border-style: solid', 'border-width: 1px', 'font-family: Arial', 'font-size: 12px', 'font-weight: bold', 'padding: 2px', 'width: 580px');
			/* agregamos el estilo de los botones */
			$this->addStyle('button', 'width: 100px');
			/* agregamos el estilo de la tabla */
			$this->addStyle('.FORMTABLE', 'background-color: #EEE');
			/* agregamos el estilo FORMTITLE */
			$this->addStyle('.FORMTITLE', 'font-weight: bold', 'padding: 5px', 'font-size: 18px');
			/* agregamos el estilo TITULOPARAM */
			$this->addStyle('.TITULOPARAM', 'font-size: 14px', 'text-align: left', 'font-weight: bold');
			/* agregamos el estilo FIELDPARAM */
			$this->addStyle('.FIELDPARAM', 'width: 150px');
			/* agregamos el estilo OFF */
			$this->addStyle('.OFF', 'color: #888');
			/* agregamos el estilo PARAM */
			$this->addStyle('.PARAM', 'text-align: left', 'font-size: 12px');
			/* agregamos el estilo para la separacion */
			$this->addStyle('.SEPARACION', 'height: 10px');
			/* agregamos el estilo para la descripcion del paquete */
			$this->addStyle('.DESCRIPT', 'text-align: left', 'font-size: 14px', 'font-style:italic', 'padding: 5px', 'border-bottom-width: 1px');
			/* agregamos el estilo para el iFrame */
			$this->addStyle('.IFRAMEINSTALL', 'width: 500px', 'border-width: 0px', 'height: 0px');
			/* agregamos el estilo para la seccion del boton Install */
			$this->addStyle('.BTNSECTION', 'border-top-width: 1px');
			/* agregamos el estilo para el mensaje instalando.. */
			$this->addStyle('.INSTALLING', 'font-size: 14px', 'color: #C80', 'font-weight: bold');
			/* agregamos el estilo para el mensaje OK */
			$this->addStyle('.INSTALLOK', 'font-size: 14px', 'color: #080', 'font-weight: bold');
			/* agregamos el estilo para el mensaje de error */
			$this->addStyle('.INSTALLERROR', 'font-size: 14px', 'color: #A00', 'font-weight: bold');
			/* finalizamos la etiqueta style */
			echo '</STYLE>';
			/* mostramos ok al mensaje */
			$this->showOK();
		}

		private function addStyle($name) {
			/* agregamos el nombre del estilo */
			echo $name . '{';
			/* obtenemos los parametros */
			$args = func_get_args();
			/* recorremos los parametros */
			for ($i = 1; $i < count($args); $i++)
				/* agregamos el valor */
				echo preg_replace('/\s+/', ' ', $args[$i]) . ';';
			/* finalizamos el estilo */
			echo '}';
		}

		private function loadJavaSctipt() {
			/* mostramos un mensaje */
			$this->show('Cargando funciones JavaScript..');
			/* iniciamos la etiqueta javascript */
			echo '<SCRIPT language=\'JavaScript\'>';
			/* cargamos la clase Install de JS */
			$this->loadJsClass('Installer');
			/* creamos la instancia de la clase Install de JS */
			$this->newInstance(__CLASS__, __CLASS__);
			/* finalizamos la etiqueta javascript */
			echo '</SCRIPT>';
		}

		private function loadJsClass($className) {
			/* mostramos un mensaje */
			$this->show('Iniciando definicion de la clase ' . $className . '..');
			/* iniciamos la clase */
			echo 'function ' . $className . '(){';
			/* agregamos el nombre de la clase */
			echo 'var __CLASS__=\'' . $className . '\';';
			/* mostramos un mensaje */
			$this->show('Agregando atributos de la clase ' . $className . '..', False);
			/* agregamos los atributos de la clase */
			$this->{'add' . $className . 'Attrs'}();
			/* mostramos ok al mensaje */
			$this->showOK();
			/* mostramos un mensaje */
			$this->show('Agregando metodos de la clase ' . $className . '..', False);
			/* agregamos los metodos de la clase */
			$this->{'add' . $className . 'Methods'}();
			/* mostramos ok al mensaje */
			$this->showOK();
			/* llamamos al metodo constructor de la clase */
			echo 'this.__construct();';
			/* finalizamos la definicion de la clase */
			echo '}';
		}

		private function addMethod($methodName, $methodContents = False) {
			/* obtenemos los argumentos para el metodo */
			$args = func_get_args();
			/* iniciamos la definicion del metodo */
			echo 'this.' . $methodName . '=function(';
			/* recorremos los parametros */
			for ($i = 2; $i < count($args); $i++)
				/* agregamos el nombre del parametro */
				echo $args[$i] . ((count($args) - 1) > $i ? ',' : '');
			/* finalizamos la cabecera del metodo */
			echo '){';
			/* iniciamos la captura de errores */
			echo 'try{';
			/* verificamos si el metodo tiene contenido */
			if ($methodContents === True)
				/* cargamos el contenido del metodo */
				$this->{'method' . ucfirst($methodName) . 'Contents'}();
			/* capturamos los errores */
			echo '}catch(e){';
			/* mostramos los errores */
			echo 'alert(e);';
			/* finalizamos la captura de errores y la definicion del metodo */
			echo '}};';
		}

		private function newInstance($objectName, $className) {
			/* mostramos un mensaje */
			$this->show('Creando instancia de la clase ' . $className . '..', False);
			/* creamos una instancia de una clase */
			echo 'var ' . $objectName . '=new ' . $className . ';';
			/* mostramos ok al mensaje */
			$this->showOK();
		}

		private function addInstallerAttrs(){}

		private function addInstallerMethods() {
			/* agregamos el metodo constructor */
			$this->addMethod('__construct');
			/* agregamos el metodo postForm */
			$this->addMethod('postForm', True, 'accion', 'destino', 'values');
			/* agregamos el metodo para verificar el form */
			$this->addMethod('validarForm', True);
			/* agregamos el metodo para obtener un elemento */
			$this->addMethod('getId', True, 'id');
			/* agregamos el metodo para mostrar el iFrame */
			$this->addMethod('showIframe', True, 'callback');
			/* agregamos el metodo para enviar el form */
			$this->addMethod('iniciarInstall', True);
			/* agregamos el metodo sendData */
			$this->addMethod('sendData', True);
			/* agregamos el metodo show */
			$this->addMethod('show', True, 'msg');
			/* agregamos el metodo showError */
			$this->addMethod('showError', True, 'msg');
			/* agregamos el metodo showOK */
			$this->addMethod('showOK', True);
			/* agregamos el metodo getPostData */
			$this->addMethod('getPostData', True);
			/* agregamos el metodo para habilitar los campos */
			$this->addMethod('enableFields', True, 'enable');
			/* agregamos el metodo para deshabilitar todo */
			$this->addMethod('disableAll', True, 'disable');
		}

		private function methodPostFormContents() {
			/* creamos un form temporal */
			echo 'var tmpForm=document.createElement(\'form\');';
			/* asignamos las propiedades */
			echo 'with(tmpForm){';
			/* especificamos el metodo como post */
			echo 'setAttribute(\'method\',\'POST\');';
			/* especificamos la ruta */
			echo 'setAttribute(\'action\',accion);';
			/* especificamos el lugar donde se ejecutara */
			echo 'setAttribute(\'target\',destino);}';
			/* recorremos los valores a agregar */
			echo 'for(var i=0;i<values.length;i++){';
			/* creamos un input */
			echo 'var tmpInput=document.createElement(\'input\');';
			/* asignamos las prppiedades */
			echo 'with(tmpInput){';
			/* especificamos el name */
			echo 'setAttribute(\'name\',values[i].name);';
			/* especificamos el valor */
			echo 'setAttribute(\'value\',values[i].value);}';
			/* agregamos el input al form */
			echo 'tmpForm.appendChild(tmpInput);}';
			/* agregamos el form al body */;
			echo 'document.body.appendChild(tmpForm);';
			/* enviamos el form */
			echo 'tmpForm.submit();';
			/* eliminamos el form del body */
			echo 'document.body.removeChild(tmpForm);';
			/* retornamos true */
			echo 'return true;';
		}

		private function methodValidarFormContents() {
			/* verificamos si especifico el path para la instalacion */
			echo 'if(this.getId(\'installDir\').value==\'\'){';
			/* retornamos false */
			echo 'return false;}';
			/* verificamos si esta habilitado el checkbox */
			echo 'if(this.getId(\'importDBs\').checked==true){';
			/* verificamos si todos los campos estan correctos */
			echo 'if(this.getId(\'installHost\').value==\'\'||this.getId(\'installUser\').value==\'\'||this.getId(\'installPass\').value==\'\'){';
			/* retornamos false */
			echo 'return false;}}';
			/* retornamos false */
			echo 'return true;';
		}

		private function methodGetIdContents() {
			/* retornamos el objeto iFrame */
			echo 'return document.getElementById(id);';
		}

		private function methodShowIframeContents() {
			/* ingresamos a un bucle */
			echo 'for(var i=0;i<=120;i++){';
			/* agrandamos el tamano height del iFrame */
			echo 'setTimeout("' . __CLASS__ . '.getId(\'estadoInstalacion\').style.height=\'"+(i*3)+"px\';",(i*4));';
			/* verificamos si el tamano actual es menor */
			echo 'if((i*10)>500){';
			/* agrandamos el tamano del iFrame */
			echo 'setTimeout("' . __CLASS__ . '.getId(\'estadoInstalacion\').style.width=\'"+(i*10)+"px\';",(i*4));}}';
			/* verificamos si tenemos un callback */
			echo 'if(callback!==undefined){';
			/* llamamos a la funcion callback */
			echo 'setTimeout("' . __CLASS__ . '."+callback+"();",(i*10));}';
		}

		private function methodSendDataContents() {
			/* verificamos si estan los datos correctos */
			echo 'if(!this.validarForm()){';
			/* salimos con una excepcion */
			echo 'throw new Error(\'No se especificaron todas las configuraciones\');}';
			/* mostramos el iFrame */
			echo 'this.showIframe(\'iniciarInstall\');';
			/* modificamos el boton */
			echo 'this.show(\'Descomprimiendo paquete de instalaci&oacute;n..\');';
			/* deshabilitamos todos los campos */
			echo 'this.disableAll(true);';
		}

		private function methodIniciarInstallContents() {
			/* agregamos la linea */
			echo 'this.getId(\'estadoInstalacion\').style.borderTopWidth=\'1px\';';
			/* enviamos el form */
			echo 'this.postForm(\'./' . $this->getTitle() . '.php\', \'estadoInstalacion\', this.getPostData());';
		}

		private function methodGetPostDataContents() {
			/* retornamos un array de valores */
			echo 'return [';
			/* enviamos la bandera en true */
			echo '{\'name\': \'' . md5('configLoaded') . '\', \'value\': true},';
			/* enviamos el installDir */
			echo '{\'name\': \'installDir\', \'value\': this.getId(\'installDir\').value},';
			/* enviamos el host */
			echo '{\'name\': \'host\', \'value\': this.getId(\'installHost\').value},';
			/* enviamos el user */
			echo '{\'name\': \'user\', \'value\': this.getId(\'installUser\').value},';
			/* enviamos el pass */
			echo '{\'name\': \'pass\', \'value\': this.getId(\'installPass\').value},';
			/* enviamos la bandera */
			echo '{\'name\': \'importDBs\', \'value\': this.getId(\'importDBs\').checked}';
			/* finalizamos el array */
			echo '];';
		}

		private function methodShowContents() {
			/* cambiamos el boton por un texto */
			echo 'this.getId(\'btnInstallSection\').innerHTML=\'<FONT class="INSTALLING">\'+msg+\'</FONT>\';';
		}

		private function methodShowErrorContents() {
			/* mostramos el mensaje de OK */
			echo 'this.getId(\'btnInstallSection\').innerHTML=\'<FONT class="INSTALLERROR">\'+msg+\'</FONT>\';';
		}

		private function methodShowOKContents() {
			/* mostramos el mensaje de OK */
			echo 'this.getId(\'btnInstallSection\').innerHTML=\'<FONT class="INSTALLOK">Instalaci&oacute;n finalizada existosamente!</FONT>\';';
		}

		private function methodEnableFieldsContents() {
			/* habilitamos el campo host */
			echo 'this.getId(\'installHost\').disabled=!enable;';
			/* habilitamos el campo user */
			echo 'this.getId(\'installUser\').disabled=!enable;';
			/* habilitamos el campo pass */
			echo 'this.getId(\'installPass\').disabled=!enable;';
 		}

 		private function methodDisableAllContents() {
			/* deshabilitamos el checkbox */
			echo 'this.getId(\'installDir\').disabled=disable;';
			/* deshabilitamos el checkbox */
			echo 'this.getId(\'importDBs\').disabled=disable;';
			/* deshabilitamos el campo host */
			echo 'this.getId(\'installHost\').disabled=disable;';
			/* deshabilitamos el campo user */
			echo 'this.getId(\'installUser\').disabled=disable;';
			/* deshabilitamos el campo pass */
			echo 'this.getId(\'installPass\').disabled=disable;';
 		}

		private function loadBodyHtml() {
			/* mostramos un mensaje */
			$this->show('Cargando seccion BODY..');
			/* iniciamos el body */
			echo '<BODY><TABLE class=\'FORMTABLE\' align=\'center\'>';
			/* cargamos un titulo */
			$this->showTitle();
			/* verificamos si el paquete tiene descripcion */
			if ($this->getDescripcion() !== False)
				/* mostramos la descripcion del paquete */
				$this->showDescript();
			/* cargamos el formulario */
			$this->loadFormHtml();
			/* finalizamos el body */
			echo '</TABLE></BODY>';
		}

		private function showTitle() {
			/* mostramos un mensaje */
			$this->show('Cargando titulo del formulario..', False);
			/* mostramos el titulo del formulario */
			echo '<TR><TD class=\'FORMTITLE\'>Instalaci&oacute;n del paquete: <FONT style=\'font-style:italic\'>' . $this->getTitle() . '</FONT></TD></TR>';
			/* mostramos ok al mensaje */
			$this->showOK();
		}

		private function showDescript() {
			/* mostramos un mensaje */
			$this->show('Cargando descripcion del paquete..', False);
			/* mostramos la descripcion del paquete */
			echo '<TR><TD class=\'DESCRIPT\'>' . $this->getDescripcion() . '</TD></TR>';
			/* mostramos ok al mensaje */
			$this->showOK();
		}

		private function loadFormHtml() {
			/* mostramos un mensaje */
			$this->show('Cargando formulario..');
			/* cargamos el form */
			$this->showForm();
			/* agregamos la seccion para el detalle de la instalacion */
			$this->showIframe();
			/* agregamos el boton instalar */
			$this->showInstallBtn();
			/* agregamos un espacio */
			echo '<TR><TD class=\'SEPARACION\'></TD></TR>';
		}

		private function showForm() {
			/* iniciamos una tabla */
			echo '<TR><TD><TABLE style=\'border-width: 0px;\'>';
			/* agregamos el campo dir */
			$this->addDirInstallField();
			/* agregamos el form de parametros de la DB */
			$this->addDBFields();
			/* finalizamos la tabla */
			echo '</TABLE></TD></TR>';
		}

		private function addDirInstallField() {
			/* mostramos un titulo */
			echo '<TR><TD class=\'TITULOPARAM\'>Directorio de instalaci&oacute;n:</TD></TR>';
			/* agregamos un campo */
			echo '<TR><TD class=\'PARAM\' style=\'text-align:center;\'><INPUT type=\'text\' id=\'installDir\'></TD></TR>';
		}

		private function addDBFields() {
			/* agregamos un espacio */
			echo '<TR><TD class=\'SEPARACION\'></TD></TR>';
			/* mostramos un titulo */
			echo '<TR><TD class=\'TITULOPARAM' . $this->getOff() . '\'>Parametros de conexion a la Base de Datos:</TD></TR>';
			/* iniciamos una tabla */
			echo '<TR><TD><TABLE style=\'border-width: 0px; width: 250px;\'>';
			/* agregamos el campo check */
			echo '<TR><TD rowspan=\'4\' style=\'width:10px;\'></TD><TD class=\'PARAM' . $this->getOff() . '\'>Importar DBs:</TD><TD style=\'text-align:left;\'>&nbsp;<INPUT class=\'FIELDPARAM\' type=\'checkbox\' id=\'importDBs\'' . ($this->getOff(True) ? '' : ' disabled') . ' onclick=\'javascript:Installer.enableFields(this.checked);\'></TD></TR>';
			/* agregamos el campo host */
			echo '<TR><TD class=\'PARAM' . $this->getOff() . '\'>Host:</TD><TD>&nbsp;<INPUT class=\'FIELDPARAM\' type=\'text\' id=\'installHost\' value=\'localhost\' disabled></TD></TR>';
			/* agregamos el campo user */
			echo '<TR><TD class=\'PARAM' . $this->getOff() . '\'>User:</TD><TD>&nbsp;<INPUT class=\'FIELDPARAM\' type=\'text\' id=\'installUser\' disabled></TD></TR>';
			/* agregamos el campo pass */
			echo '<TR><TD class=\'PARAM' . $this->getOff() . '\'>Pass:</TD><TD>&nbsp;<INPUT class=\'FIELDPARAM\' type=\'password\' id=\'installPass\' disabled></TD></TR>';
			/* finalizamos la tabla */
			echo '</TABLE></TD></TR>';
		}

		private function getOff($true = False) {
			/* retornamos si deshabilitamos el titulo */
			return (
				/* verificamos si hay una DB */
				$this->withDBs === True ?
				/* deshabilitamos el titulo */
				($true === True ? True : '') :
				/* retornamos true */
				($true === True ? False : ' OFF')
			);
		}

		private function showIframe() {
			/* agregamos un espacio */
			echo '<TR><TD class=\'SEPARACION\'></TD></TR>';
			/* agregamos el iFrame para la instalacion */
			echo '<TR><TD><IFRAME id=\'estadoInstalacion\' name=\'estadoInstalacion\' class=\'IFRAMEINSTALL\'></IFRAME></TD></TR>';
		}

		private function showInstallBtn() {
			/* agregamos un espacio */
			echo '<TR><TD class=\'SEPARACION BTNSECTION\'></TD></TR>';
			/* mostramos un boton para iniciar la instalacion **/
			echo '<TR><TD id=\'btnInstallSection\'><BUTTON onclick=\'javascript:' . __CLASS__ . '.sendData();\' id=\'btnInstall\'>Instalar</BUTTON></TD></TR>';
		}

		private function saveInstallData($installData) {
			/* seteamos el tiempo maximo de ejecucion en 10 minutos */
			set_time_limit(600);
			/* mostramos un mensaje */
			$this->show('Almacenando datos de la instalacion..', False);
			/* almacenamos los datos */
			$this->installData = unserialize(base64_decode($installData));
			/* mostramos ok al mensaje */
			$this->showOK();
		}

		private function runInstall() {
			/* mostramos un mensaje */
			$this->show('Iniciando instalacion..');
			/* separamos los datos */
			$this->separarDatos();
			/* obtenemos el dir de trabajo actual */
			$actualDir = getcwd();
			/* nos posicionamos en la raiz */
			chdir('/');
			/* creamos la estructura de directorios */
			$this->buildTree();
			/* creamos los ficheros */
			$this->buildFiles();
			/* nos posicionamos el el directorio original */
			chdir($actualDir);
			/* verificamos si hay dbs */
			if ($this->dbData !== False)
				/* cargamos la DB */
				$this->buildDBs();
			/* mostramos el mensaje de OK */
			echo '<SCRIPT languaje=\'javascript\'>parent.Installer.showOK();</SCRIPT>';
		}

		private function separarDatos() {
			/* almacenamos la estructura de directorios */
			$this->saveTree();
			/* almacenamos los ficheros */
			$this->saveFiles();
			/* almacenamos los datos de la DB */
			$this->saveDbData();
		}

		private function saveTree() {
			/* mostramos un mensaje */
			$this->show('Descomprimiendo datos del arbol de directorios..', False);
			/* almacenamos el arbol */
			$this->tree = Crypter::decrypt($this->installData['tree'], $this->getKey());
			/* verificamos si se esta ok */
			if (gettype($this->tree) !== 'array')
				/* salimos con una excepcion */
				$this->newException('El arbol de directorios esta corrupto');
			/* mostramos ok al mensaje */
			$this->showOK();
		}

		private function saveFiles() {
			/* mostramos un mensaje */
			$this->show('Descomprimiendo datos de ficheros..', False);
			/* almacenamos los ficheros */
			$this->files = Crypter::decrypt($this->installData['files'], $this->getKey());
			/* verificamos si se esta ok */
			if (gettype($this->files) !== 'array')
				/* salimos con una excepcion */
				$this->newException('Los datos de los ficheros estan corruptos');
			/* mostramos ok al mensaje */
			$this->showOK();
		}

		private function saveDbData() {
			/* mostramos un mensaje */
			$this->show('Descomprimiendo datos de la base de datos..', False);
			/* verificamos si se especifico una DB */
			if ($this->installData['db'] === False)
				/* salimos con un mensaje */
				$this->show($this->red('El paquete no posee una base de datos'));
			/* verificamos si se especifico una DB */
			if ($_POST['importDBs'] === 'false')
				/* salimos con un mensaje */
				$this->show($this->red('Se omite la importacion de las bases de datos'));
			/* verificamos si se cumplen cuanquiera de las falsas */
			if (($this->installData['db'] === False) || ($_POST['importDBs'] === 'false')) {
				/* almacenamos false en la DB */
				$this->dbData = False;
				/* retornamos false */
				return False;
			}
			/* almacenamos los datos de la DB */
			$this->dbData = Crypter::decrypt($this->installData['db'], $this->getKey());
			/* verificamos si se esta ok */
			if (gettype($this->dbData) !== 'array')
				/* salimos con una excepcion */
				$this->newException('Los datos de la base de datos estan corruptos');
			/* mostramos ok al mensaje */
			$this->showOK();
		}

		private function buildTree() {
			/* mostramos un mensaje */
			$this->show('Creando arbol de directorios..', False);
			/* verificamos si existe el directorio */
			if (!file_exists($this->getInstallDir()))
				/* salimos con una excepcion */
				$this->newException('El directorio ' . $this->fileFormat($this->getInstallDir()) . ' no existe');
			/* verificamos que sea un directorio */
			if (!is_dir($this->getInstallDir()))
				/* salimos con una excepcion */
				$this->newException('La ruta ' . $this->fileFormat($this->getInstallDir()) . ' no es un directorio');
			/* verificamos si tenemos permisos de escritura en el directorio */
			if (!is_writable($this->getInstallDir()))
				/* salimos con una excepcion */
				$this->newException('No se poseen permisos de escritura en el directorio ' . $this->fileFormat($this->getInstallDir()));
			/* mostramos un salto de linea */
			$this->show('');
			/* recorremos el arbol */
			foreach ($this->tree AS $folder) {
				/* mostramos un mensaje */
				$this->show('Creando el directorio ' . $this->fileFormat($folder) . '..', False); usleep(10000);
				/* verificamos si el directorio no existe */
				if (file_exists($this->getInstallDir() . '/' . $folder))
					/* mostramos un mensaje */
					$this->show($this->blue('El directorio ya existe..'), False);
				else {
					/* creamos el directorio */
					mkdir($this->getInstallDir() . '/' . $folder, 0777, True);
				}
				/* verificamos si podemos escribir en el directorio */
				if (!is_writable($this->getInstallDir() . '/' . $folder))
					/* salimos con una excepcion */
					$this->newException('No se poseen permisos de escritura en el directorio');
				/* asignamos permisos completos al directorio */
				chmod($this->getInstallDir() . '/' . $folder, 0777);
				/* mostramos ok al mensaje */
				$this->showOK();
			}
		}

		private function buildFiles() {
			/* mostramos un mensaje */
			$this->show('Creando contenido de los ficheros..');
			/* recorremos los ficheros */
			foreach ($this->files AS $fileName => $fileData) {
				/* mostramos un mensaje */
				$this->show('Cargando contenido del fichero ' . $this->fileFormat($fileName) . '..', False); usleep(20000);
				/* verificamos si el fichero existe */
				if (file_exists($this->getInstallDir() . '/' . $fileName))
					/* mostramos un mensaje */
					$this->show($this->red('El fichero ya existe, se omite'));
				else {
					/* creamos el fichero con el contenido */
					file_put_contents($this->getInstallDir() . '/' . $fileName, Crypter::decrypt($fileData['contents'], $fileName));
					/* asignamos los permisos al fichero */
					chmod($this->getInstallDir() . '/' . $fileName, 0777);
					/* mostramos ok al mensaje */
					$this->showOK();
				}
			}
		}

		private function buildDBs() {
			/* cargamos los parametros de configuracion */
			$this->initDBConection();
			/* mostramos un mensaje */
			$this->show('Iniciando creacion de las bases de datos..');
			/* recorremos las bases de datos */
			foreach ($this->dbData AS $dbName => $dbTables) {
				/* creamos la db */
				$this->crearDB($dbName);
				/* recorremos las tablas */
				foreach ($dbTables AS $tableName => $table) {
					/* creamos la tabla */
					$this->crearTabla($table['structure'], $tableName);
					/* cargamos los datos de la tabla */
					$this->populateTable($table['data'], $tableName);
				}
			}
		}

		private function initDBConection() {
			/* creamos una instancia de MySQLProcess */
			$this->dbBuilder = new MySQLProcess;
			/* mostramos un mensaje */
			$this->show('Cargando parametros de conexion..', False);
			/* seteamos el host */
			$this->dbBuilder->setHost($_POST['host']);
			/* seteamos el user */
			$this->dbBuilder->setUser($_POST['user']);
			/* seteamos el pass */
			$this->dbBuilder->setPass($_POST['pass']);
			/* conectamos */
			if(!$this->dbBuilder->conectar())
				/* salimos con una excepcion */
				$this->newException('Se produjo un error al conectar con el servidor de bases de datos');
			/* mostramos ok al mensaje */
			$this->showOK();
		}

		private function crearDB($dbName) {
			/* mostramos un mensaje */
			$this->show('Creando la base de datos ' . $this->classFormat($dbName) . '..', False);
			/* creamos la DB */
			$this->dbBuilder->ejecutarSQL('CREATE DATABASE ' . $dbName);
			/* seleccionamos la db */
			$this->dbBuilder->seleccionarDB($dbName);
			/* mostramos ok al mensaje */
			$this->showOK();
		}

		private function crearTabla($tableStructure, $tableName) {
			/* mostramos un mensaje */
			$this->show('Creando la tabla ' . $this->italic($this->blue($tableName)) . '..', False);
			/* creamos la tabla */
			$this->dbBuilder->ejecutarSQL(Crypter::decrypt($tableStructure, $tableName));
			/* mostramos ok al mensaje */
			$this->showOK();
		}

		private function populateTable($tableData, $tableName) {
			/* mostramos un mensaje */
			$this->show('Cargando registros de la tabla..', False);
			/* obtenemos el array de inserts */
			$inserts = Crypter::decrypt($tableData, $tableName);
			/* recorremos los inserts */
			foreach ($inserts AS $insert)
				/* cargamos el insert */
				$this->dbBuilder->ejecutarSQL($insert);
			/* mostramos ok al mensaje */
			$this->showOK();
			/* mostramos la cantidad de registros almacenados */
			$this->show('Cantidad de registros creados: ' . $this->bold(count($inserts)));
		}

		private function getInstallDir() {
			/* retornamos el directorio de instalacion */
			return (substr($_POST['installDir'], -1) == '/' ? substr($_POST['installDir'], 0, -1) : $_POST['installDir']);
		}

		private function getKey() {
			/* retornamos la clave */
			return md5(preg_replace('/\s+/', '_', $this->getTitle()) . $this->getAuthor());
		}

		private function getAuthor() {
			/* retornamos el autor */
			return $this->author;
		}

		private function getTitle() {
			/* retornamos el titulo del paquete */
			return $this->title;
		}

		private function getDescripcion() {
			/* retornamos la descripcion del paquete */
			return $this->descrip;
		}

		private function catchExceptions($method = Null, $parentError = False) {
			/* ingresamos a un control de errores para capturar mis excepciones */
			try {
				/* ingresamos a un control de errores para capturar las excepciones de ejecucion */
				try {
					/* realizamos algunas verificaciones */
					$this->verificarMetodo($method);
					/* obtenemos los parametros recibidos */
					$args = func_get_args();
					/* llamamos al metodo enviando los parametros */
					eval('$this->' . $method . '(' . $this->buildArgs($args) . ');');
				/* capturamos las excepciones */
				} catch (Exception $e) {
					/* capturamos todos los errores y los transformamos en mi excepcion */
					$this->newException($e);
				}
			/* capturamos mis excepciones */
			} catch (MyException $e) {
				/* si se produjo una excepcion la manejamos con el metodo 'show' */
				$this->show($e->getMensaje());
				/* verificamos si enviamos al parent el error */
				if ($parentError === True)
					/* enviamos el error */
					echo '<SCRIPT languaje=\'javascript\'>parent.Installer.showError(\'Se produjo un error en la instalaci&oacute;n\');</SCRIPT>';
			}
		}
	}
?>